/*
 * Created by Jaren at 2021/11/28 9:54
 */
import 'dart:typed_data';

import 'package:binary/binary.dart';
import 'package:inmotion_protocol/common/compact.dart';
import 'package:inmotion_protocol/common/exceptions.dart';
import 'package:inmotion_protocol/common/product_model.dart';
import 'package:inmotion_protocol/common/product_version.dart';
import 'package:inmotion_protocol/lorin/bean/base/real_time_info.dart';
import 'package:inmotion_protocol/util/byte_util.dart';

class EucAllRealTimeInfo extends AbsAllRealTimeInfo {
  EucAllRealTimeInfo(AbsRealTimeInfo realTimeInfo, AbsRealTimeState realTimeState, AbsRealTimeError realTimeError) : super(realTimeInfo, realTimeState, realTimeError);
}

abstract class EucRealTimeInfo extends AbsRealTimeInfo {
  Int16 torque = Int16.zero;
  Int16 batteryOutputPower = Int16.zero;
  Int16 motorOutputPower = Int16.zero;

  Int16 outputRate = Int16.zero;

  Int8 batteryMode = Int8.zero;
  Uint16 batteryLevelForRide = Uint16.zero;
  Uint16 estimatedTotalMileage = Uint16.zero;
  Int16 mosTemp = Int16.zero;
  Int16 motorTemp = Int16.zero;
  Int16 batteryTemp = Int16.zero;
  Int16 boardTemp = Int16.zero;
  Int16 lampTemp = Int16.zero;
  Int16 pitchAngle = Int16.zero;
  Int16 pitchAimAngle = Int16.zero;
  Int16 rollAngle = Int16.zero;
  Int16 speedingBrakingAngle = Int16.zero;
  Int16 dynamicCurrentLimit = Int16.zero;
  Uint16 dynamicSpeedLimit = Uint16.zero;
  Uint8 brightness = Uint8.zero;
  Uint8 lightBrightness = Uint8.zero;
  Int16 cpuTemp = Int16.zero;
  Int16 imuTemp = Int16.zero;

  EucRealTimeInfo(ProductModel model, VersionWrapper version) : super(model, version);
}

abstract class EucRealTimeState extends AbsRealTimeState {
  Uint4 mcMode = Uint4.zero;
  Uint4 motorState = Uint4.zero;
  Uint4 chargeState = Uint4.zero;
  Uint4 liftedState = Uint4.zero;
  Uint4 tailLightState = Uint4.zero;
  Uint4 backupBatteryState = Uint4.zero;
  Uint4 brakeState = Uint4.zero;
  Uint4 slowDownState = Uint4.zero;

  EucRealTimeState(ProductModel model, VersionWrapper version) : super(model, version);
}

abstract class EucRealTimeError extends AbsRealTimeError {
  Uint4 iPhaseSensorState = Uint4.zero;
  Uint4 iBusSensorState = Uint4.zero;
  Uint4 imuSensorState = Uint4.zero;
  Uint4 controllerCom1State = Uint4.zero;
  Uint4 controllerCom2State = Uint4.zero;
  Uint4 bleCom1State = Uint4.zero;
  Uint4 bleCom2State = Uint4.zero;
  Uint4 mosTempSensorState = Uint4.zero;
  Uint4 motorTempSensorState = Uint4.zero;
  Uint4 batteryTempSensorState = Uint4.zero;
  Uint4 boardTempSensorState = Uint4.zero;
  Uint4 fanState = Uint4.zero;
  Uint4 rtcState = Uint4.zero;
  Uint4 externalRomState = Uint4.zero;
  Uint4 vBusSensorState = Uint4.zero;
  Uint4 vBatterySensorState = Uint4.zero;
  Uint4 canNotPowerOffState = Uint4.zero;
  Uint4 canNotChargeState = Uint4.zero;

  Uint4 underVoltageState = Uint4.zero;
  Uint4 overVoltageState = Uint4.zero;
  Uint4 overBusCurrentState = Uint4.zero; // 总电流过大警告
  Uint4 lowBatteryState = Uint4.zero; // 低电状态，0-电量正常，1~3低电等级
  Uint4 overBoardTempState = Uint4.zero; // 主板高温区温度异常警告
  Uint4 overSpeedState = Uint4.zero; // 超速警告
  Uint4 outputSaturationState = Uint4.zero; // 矢量电压饱和警告
  Uint4 motorSpinState = Uint4.zero; // 空转警告
  Uint4 motorBlockState = Uint4.zero; // 电机堵转警告
  Uint4 postureState = Uint4.zero; // 倾角过大警告
  Uint4 riskBehaviourState = Uint4.zero; // 危险骑行警告
  Uint4 motorNoLoadState = Uint4.zero; // 电机空载状态
  Uint4 noSelfTestState = Uint4.zero; // 存在必要的自检项未进行或未通过
  Uint4 compatibilityState = Uint4.zero; // 各组件软件不兼容警告
  Uint4 powerKeyLongPressState = Uint4.zero; // 电源键被长时间按下警告
  Uint4 forceDfuState = Uint4.zero; // 强制固件升级
  Uint4 deviceLockState = Uint4.zero; // 设备被锁定
  Uint4 cpuOverTempState = Uint4.zero; // CPU过温警告
  Uint4 imuOverTempState = Uint4.zero; // IMU过温警告
  Uint4 hwCompatibilityState = Uint4.zero; // 硬件不兼容警告
  Uint4 fanLowSpeedState = Uint4.zero; // 风扇转速过低警告
  Uint4 someBatteriesNotWorkState = Uint4.zero; // 部分电池未工作警告
  Uint4 batteryNotCaliState = Uint4.zero; // 电池未自检异常
  Uint4 chargeDangerWarningLevel = Uint4.zero; // 快充充电存在风险警告等级
  Uint4 chargeDangerWarningHandledState = Uint4.zero; // 快充充电存在风险警告已处理标识
  Uint4 lockedBySafetyIssueState = Uint4.zero; // 车辆存在安全相关的风险已被锁定标识

  EucRealTimeError(ProductModel model, VersionWrapper version) : super(model, version);

  hasVisibleError() {
    return ((originalValue.value << 16) >> 16) == 0;
  }

  hasVisibleWarning() {
    return (originalValue.value >> 16) == 0;
  }
}

/// 实时电池信息
class EUCBatteryRealTimeInfo extends AbsBatteryRealTimeInfo {
  EUCSingleBatteryRealTimeInfo? _battery1;
  EUCSingleBatteryRealTimeInfo? _battery2;
  Uint16 chargeVoltage = Uint16.zero;
  Int16 chargeCurrent = Int16.zero;

  EUCBatteryRealTimeInfo(ProductModel model, VersionWrapper version) : super(model, version);

  @override
  void initCompact() {
    compact = _DefaultEUCBatteryRealTimeInfo(model, version);
  }

  get battery1 {
    if (_battery1 == null) throw ProtocolParseException("Unexpected exception. Please call [fromBytes] to gen battery info first!");
    return _battery1!;
  }

  get battery2 {
    if (_battery2 == null) throw ProtocolParseException("Unexpected exception. Please call [fromBytes] to gen battery info first!");
    return _battery2!;
  }

  @override
  String toString() {
    return 'EUCBatteryRealTimeInfo{_battery1: $_battery1, _battery2: $_battery2, chargeVoltage: $chargeVoltage, chargeCurrent: $chargeCurrent}';
  }
}

class _DefaultEUCBatteryRealTimeInfo extends Compact<EUCBatteryRealTimeInfo> {
  final ProductModel _model;
  final VersionWrapper _versionWrapper;

  _DefaultEUCBatteryRealTimeInfo(this._model, this._versionWrapper);

  @override
  void fromBytes(EUCBatteryRealTimeInfo output, Uint8ClampedList bytes, int offset) {
    output._battery1 = EUCSingleBatteryRealTimeInfo(_model, _versionWrapper);
    output._battery1!.fromBytes(bytes, offset);
    offset += output._battery1!.length();
    output._battery2 = EUCSingleBatteryRealTimeInfo(_model, _versionWrapper);
    output._battery2!.fromBytes(bytes, offset);
    offset += output._battery2!.length();
    output.chargeVoltage = ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;
    output.chargeCurrent = ByteUtil.bytes2Int16Le(bytes, offset);
  }

  @override
  int length() {
    return 20;
  }
}

class EUCSingleBatteryRealTimeInfo extends AbsBatteryRealTimeInfo {
  Uint16 voltage = Uint16.zero;
  Int16 current = Int16.zero;
  Int8 temp = Int8.zero;
  Uint4 detected = Uint4.zero;
  Uint4 enable = Uint4.zero;
  Uint4 charge = Uint4.zero;
  Uint4 errorLogic = Uint4.zero;
  Uint4 errorSignal = Uint4.zero;
  Uint4 errorVoltageSensor = Uint4.zero;
  Uint4 errorCurrentSensor = Uint4.zero;
  Uint4 errorCannotCharge = Uint4.zero;
  Uint4 errorOverCharge = Uint4.zero;
  Uint4 errorOverDischarge = Uint4.zero;
  Uint4 errorOverTemp = Uint4.zero;

  EUCSingleBatteryRealTimeInfo(ProductModel model, VersionWrapper version) : super(model, version);

  @override
  void initCompact() {
    compact = _DefaultEUCSingleBatteryRealTimeInfo();
  }

  @override
  String toString() {
    return 'EUCSingleBatteryRealTimeInfo{voltage: $voltage, current: $current, temp: $temp, detected: $detected, enable: $enable, charge: $charge, errorLogic: $errorLogic, errorSignal: $errorSignal, errorVoltageSensor: $errorVoltageSensor, errorCurrentSensor: $errorCurrentSensor, errorCannotCharge: $errorCannotCharge, errorOverCharge: $errorOverCharge, errorOverDischarge: $errorOverDischarge, errorOverTemp: $errorOverTemp}';
  }
}

class _DefaultEUCSingleBatteryRealTimeInfo extends Compact<EUCSingleBatteryRealTimeInfo> {
  @override
  void fromBytes(EUCSingleBatteryRealTimeInfo output, Uint8ClampedList bytes, int offset) {
    output.voltage = ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;
    output.current = ByteUtil.bytes2Int16Le(bytes, offset);
    offset += 2;
    output.temp = ByteUtil.toInt8(ByteUtil.bytes2Int8Le(bytes, offset).value + 80);
    offset++;

    output.detected = ByteUtil.bitValue(bytes[offset], 0, 1);
    output.enable = ByteUtil.bitValue(bytes[offset], 1, 1);
    output.charge = ByteUtil.bitValue(bytes[offset], 2, 1);
    // 剩余5bit保留

    offset++;
    output.errorLogic = ByteUtil.bitValue(bytes[offset], 0, 1);
    output.errorSignal = ByteUtil.bitValue(bytes[offset], 1, 1);
    output.errorVoltageSensor = ByteUtil.bitValue(bytes[offset], 2, 1);
    output.errorCurrentSensor = ByteUtil.bitValue(bytes[offset], 3, 1);
    output.errorCannotCharge = ByteUtil.bitValue(bytes[offset], 4, 1);
    output.errorOverCharge = ByteUtil.bitValue(bytes[offset], 5, 1);
    output.errorOverDischarge = ByteUtil.bitValue(bytes[offset], 6, 1);
    output.errorOverTemp = ByteUtil.bitValue(bytes[offset], 7, 1);
  }

  @override
  int length() {
    return 8;
  }
}
